/******************************************************************************
 *      Mestrado em Ciência da Computação - UFMS
 *		Redes de Computadores - Prof. Dr. Ronaldo Alves Ferreira
 *		Alunos: Geraldo Landre, Marcel Tolentino, Vinícius Bueno
 *****************************************************************************/

#ifndef THREAD_H
#define	THREAD_H

#include "defines.h"
#include "thread_param.h"
#include "port.h"


//
// Definir erros aqui
//
typedef enum {
    //THERR_NOTRECVD        = -1, // Mais de uma mensagem foi enviada e nao foi recebida
    THERR_NOTNEW            = -1,
    THERR_NOTPREPARED       = -2,
    THERR_NOTSTARTED        = -3,
    THERR_DESTNOTSTARTED    = -4,
    THERR_BUFFBOUND         = -5,
} thread_error;

//
// Estados possiveis para as threads
//
typedef enum {
    THREAD_FREE         = 1,
    THREAD_NEW          = 2,
    THREAD_READY        = 3,
    THREAD_RUNNING      = 4,
    THREAD_SUSPENDED    = 5
} thread_state;

// ----------------------------- THREAD ----------------------------------

// estrutura a ser usada para manipular threads
typedef struct {
    pthread_t *thread;
    int buffer;

    void *function;
    void *params;

    sem_t suspend_mutex;

    thread_state state;
} thread;

/**
 * Cria uma nova thread, com buffer para mensagens atribuido.
 * Insere nova thread no array de threads
 * @param bufflength
 * @return id da thread
 */
int newthread();
int _newthread(u_short bufflength);

int newthread_kernel();
int _newthread_kernel(u_short bufflength);

/**
 * Desaloca a thread cujo id foi passado
 * @param id id da thread
 */
void freethread(u_short i);

/**
 * Atribui a funcao que serah executada pela thread
 * @param id id da thread
 * @param func ponteiro para a funcao
 * @param params ponteiro para os parametros
 */
int thread_setfunction(u_short i, void *func, void *params);

/**
 * Inicia a execucao da thread
 * @param id id da thread
 */
int thread_start(u_short id);
/**
 * Suspende a execucao da thread
 * @param id id da thread
 */
void thread_suspend(u_short id);
/**
 * Resume a execucao de uma thread suspensa
 * @param id id da thread
 */
void thread_resume(u_short id);
/**
 * Caso a thread esteja suspensa, espera ate uma chamada
 * para resume
 * @param id id da thread a esperar
 */
void thread_wait(u_short id);

/**
 * Envia uma mensagem para a thread cujo id foi passado
 * @param id id da thread para a qual se deseja enviar a msg
 * @param msg mensagem a ser enviada
 * @return codigo da mensagem enviada ou um numero negativo em caso de erro
 */
int thread_sendmsg(u_short id_dest, int msg);
// caso precise ser usado no processo principal
void _thread_sendmsg(u_short id_dest, int msg);
/**
 * espera por uma mensagem
 * @return mensagem recebida
 */
int thread_recvmsg(u_short i);

/**
 * conta quantas mensagens existem na fila da thread i
 * @param i id da thread
 * @return num de msgs na fila da thread i
 */
u_short thread_countmsg(u_short i);

u_short thread_getport(u_short i);
// ---------------------- BUFFER de THREADS ------------------------------------

#define TCP_NTHREADS 4 // input, output, timer, udp

thread **thread_buff;
sync_queue_int *free_threads;
sem_t thread_buff_mutex;
int thread_buff_length;

// inicializa o buffer de threads
void init_thread_buff(int length);
// libera o buffer de threads
void destroy_thread_buff();

//
// testing
//
const char* str_thread_state(thread_state state);
const char* str_thread_error(int error);
void print_thread(int i);
void print_thread_buff();

#endif	/* THREAD_H */

